#include "urlnode.h"
#include <QDebug>

UrlNode::UrlNode() : m_type(INVALID)
{}


UrlNode::UrlNode(const QString &nodeStr)
{
    parse(nodeStr);
}

UrlNode::UrlNode(SelectorType selectorType, const QVariant &selectorData) :
    m_type(selectorType), m_data(selectorData)
{}

UrlNode::SelectorType UrlNode::selectorType() const
{
    return m_type;
}

QVariant UrlNode::selectorData() const
{
    return m_data;
}

bool UrlNode::match(const UrlNode &master, const UrlNode &matching)
{
    UrlNode::SelectorType type = master.selectorType();
    UrlNode::SelectorType matchingType = matching.selectorType();
    if (type == UrlNode::NAME && matchingType == UrlNode::NAME) {
        return master.selectorData() == matching.selectorData();
    } /*else if (type == UrlNode::REGEXP && matchingType == UrlNode::NAME) {
        return master.selectorData().toRegExp()
                .exactMatch(matching.selectorData().toString());
    } */else if (type == UrlNode::GROUP_OR &&
               (matchingType == UrlNode::GROUP_AND
                || matchingType == UrlNode::GROUP_OR)) {
        QStringList master_groups = master.selectorData().toStringList();
        QStringList matching_groups = matching.selectorData().toStringList();
        for (int i = 0; i < matching_groups.count(); ++i)
            if (master_groups.contains(matching_groups[i]))
                return true;
        return false;
    } else if (type == UrlNode::GROUP_AND &&
               (matchingType == UrlNode::GROUP_AND
                || matchingType == UrlNode::GROUP_OR)) {
        QStringList master_groups = master.selectorData().toStringList();
        QStringList matching_groups = matching.selectorData().toStringList();
        for (int i = 0; i < master_groups.count(); ++i)
            if (!matching_groups.contains(master_groups[i]))
                return false;
        return true;
    } else if (type == UrlNode::ALL) {
        return true;
    }
    return false;
}

bool UrlNode::match(const UrlNode &master,
                    const QString &matchingName,
                    const QStringList &matchingGroups)
{
    UrlNode::SelectorType type = master.selectorType();
    if (type == UrlNode::NAME) {
        return master.selectorData() == matchingName;
    } /*else if (type == UrlNode::REGEXP) {
        return master.selectorData().toRegExp()
                .exactMatch(matchingName);
    } */else if (type == UrlNode::GROUP_OR) {
        QStringList master_groups = master.selectorData().toStringList();
        for (int i = 0; i < matchingGroups.count(); ++i)
            if (master_groups.contains(matchingGroups[i]))
                return true;
        return false;
    } else if (type == UrlNode::GROUP_AND) {
        QStringList master_groups = master.selectorData().toStringList();
        for (int i = 0; i < master_groups.count(); ++i)
            if (!matchingGroups.contains(master_groups[i]))
                return false;
        return true;
    } else if (type == UrlNode::ALL) {
        return true;
    }
    return false;
}

QString UrlNode::toString() const
{
    switch (m_type) {
    case INVALID:
        return "<invalid>";
    case NAME:
        return QString("<name>:%1").arg(m_data.toString());
    case ALL:
        return "<*all*>";
    case GROUP_AND:
        return QString("<group&&>:%1").arg(m_data.toStringList().join(','));
    case GROUP_OR:
        return QString("<group||>:%1").arg(m_data.toStringList().join(','));
//    case REGEXP:
//        return QString("<regexp>:%1").arg(m_selector.toString());
    case SKIP:
        return "<...skip...>";
    }
    return "<unknown>";
}

QDataStream &operator <<(QDataStream &out, const UrlNode &node)
{
    out << (quint32)node.selectorType() << node.selectorData();
    return out;
}

QDataStream &operator >>(QDataStream &in, UrlNode &node)
{
    QVariant selectorData;
    quint32 selectorType;
    in >> selectorType >> selectorData;
    node = UrlNode((UrlNode::SelectorType)selectorType, selectorData);
    return in;
}

void UrlNode::parse(const QString &node_str)
{
    if (node_str[0] == '*') {
        m_type = ALL;
    } else if (node_str == "...") {
        m_type = SKIP;
    } else if (node_str[0] == '[') {
        int max = 0; int count = 0;
        for (int i = 0; i < node_str.length(); ++i) {
            QChar c = node_str[i];
            if (c == '[') count++;
            if (count > max) max = count;
            if (c == ']') count--;
        }
        m_type = max > 1 ? GROUP_AND : GROUP_OR;
        QStringList result;
        foreach(QString g, node_str.split('[', QString::SkipEmptyParts)) {
            g.remove(']');
            result << g.trimmed();
        }
        m_data = result;
    } else {
        m_type = NAME;
        m_data = node_str;
    }
}
